package gameManager;

import java.util.ArrayList;
import java.util.LinkedList;
import common.DominoState;
import common.Piece;
import common.Side;

/**
 * This class should not be used by the agent.
 * 
 */
public class GameState extends DominoState {

    private LinkedList<Piece> upperPlayerPieces;
    private LinkedList<Piece> downPlayerPieces;
    private LinkedList<Integer> numbersPlayedLeft;
    private LinkedList<Integer> numbersPlayedRight;

    public GameState() {
        numbersPlayedLeft = new LinkedList<>();
        numbersPlayedRight = new LinkedList<>();
    }

    public void restart(LinkedList<Piece> firstPlayerPieces, LinkedList<Piece> secondPlayerPieces) {
        super.restart();
        this.upperPlayerPieces = firstPlayerPieces;
        this.downPlayerPieces = secondPlayerPieces;
        numbersPlayedLeft.clear();
        numbersPlayedRight.clear();
        fireGameChanged(null);
    }

    @Override
    public boolean placePiece(Side side, Piece piece) {
        if (super.isValidMove(side, piece) && playedPieces.size() > 0) {
            if (side == Side.LEFT) {
                numbersPlayedLeft.addLast((int) leftValue);
            } else {
                numbersPlayedRight.addLast((int) rightValue);
            }
        }
        if (!super.placePiece(side, piece)) {
            return false;
        }
        if (playedPieces.size() == 1) {
            numbersPlayedLeft.addLast((int) leftValue);
            numbersPlayedRight.addLast((int) rightValue);
        } else if (side == Side.LEFT) {
            numbersPlayedLeft.addLast((int) leftValue);
        } else {
            numbersPlayedRight.addLast((int) rightValue);
        }

        upperPlayerPieces.remove(piece);
        downPlayerPieces.remove(piece);

        fireGameChanged(null);
        return true;
    }

    public LinkedList<Integer> getNumbersPlayedLeft() {
        return numbersPlayedLeft;
    }

    public LinkedList<Integer> getNumbersPlayedRight() {
        return numbersPlayedRight;
    }

    public LinkedList<Piece> getUpperPlayerPieces() {
        return upperPlayerPieces;
    }

    public LinkedList<Piece> getDownPlayerPieces() {
        return downPlayerPieces;
    }


    //Deu um NullPointerException neste método no if. Ou seja, a peça estava a null. Estranho...
    public boolean upperPlayerCanPlay() {
        LinkedList<Piece> playerPieces = (LinkedList<Piece>) upperPlayerPieces.clone();
        for (Piece piece : playerPieces) {
            if (piece.hasValue(leftValue) || piece.hasValue(rightValue)) {
                return true;
            }
        }
        return false;
    }
    
    public boolean downPlayerCanPlay() {
        LinkedList<Piece> playerPieces = (LinkedList<Piece>) downPlayerPieces.clone();
        for (Piece piece : playerPieces) {
            if (piece.hasValue(leftValue) || piece.hasValue(rightValue)) {
                return true;
            }
        }
        return false;
    }

    public boolean isEndOfGameState() {
        return upperPlayerPieces.isEmpty() || downPlayerPieces.isEmpty() || (!upperPlayerCanPlay() && !downPlayerCanPlay());
    }

    public String getWinner() {
        int pointsUpperPlayer = getPlayerSum(upperPlayerPieces);
        int pointsDownPlayer = getPlayerSum(downPlayerPieces);
        return pointsDownPlayer > pointsUpperPlayer ?
                "Upper player" : 
                pointsUpperPlayer > pointsDownPlayer ? "Down player" : "Draw";
    }
    
    private int getPlayerSum(LinkedList<Piece> playerPieces) {
        int sum = 0;
        for (Piece piece : playerPieces) {
            sum += piece.getValuesSum();
        }
        return sum;
    }    
    
    //Listeners
    private transient ArrayList<StateListener> listeners = new ArrayList<>(3);

    public synchronized void removeGameListener(StateListener l) {
        if (listeners != null && listeners.contains(l)) {
            listeners.remove(l);
        }
    }

    public synchronized void addGameListener(StateListener l) {
        if (!listeners.contains(l)) {
            listeners.add(l);
        }
    }

    public void fireGameChanged(StateEvent pe) {
        for (StateListener listener : listeners) {
            listener.stateChanged(null);
        }
    }
}
